/*
 * File    : ConfigurationChecker.java
 * Created : 8 oct. 2003 23:04:14
 * By      : Olivier 
 * 
 * Azureus - a Java Bittorrent client
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details ( see the LICENSE file ).
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.gudy.azureus2.core3.config.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.security.SESecurityManager;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.RandomUtils;
import org.gudy.azureus2.core3.util.SimpleTimer;
import org.gudy.azureus2.core3.util.SystemProperties;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.TimerEvent;
import org.gudy.azureus2.core3.util.TimerEventPerformer;
import org.gudy.azureus2.core3.util.TimerEventPeriodic;
import org.gudy.azureus2.platform.PlatformManager;
import org.gudy.azureus2.platform.PlatformManagerCapabilities;
import org.gudy.azureus2.platform.PlatformManagerFactory;

import com.aelitis.azureus.core.custom.CustomizationManagerFactory;
import com.aelitis.azureus.core.speedmanager.impl.SpeedManagerImpl;
import com.aelitis.azureus.core.util.FeatureAvailability;

/**
 * 
 * The purpose of this class is to provide a way of checking that the config file contains valid values when azureus is started.
 * 
 * 
 * @author Olivier
 * 
 */
public class ConfigurationChecker {
    private static final LogIDs LOGID = LogIDs.CORE;

    private static boolean system_properties_set = false;

    private static boolean checked = false;
    private static boolean new_install = false;

    private static AEMonitor class_mon = new AEMonitor("ConfigChecker");

    private static boolean new_version = false;

    protected static void setSystemProperties() {
        try {
            class_mon.enter();

            if (system_properties_set) {

                return;
            }

            COConfigurationManager.preInitialise();

            //

            String app_path = SystemProperties.getApplicationPath();
            String user_path = SystemProperties.getUserPath();

            loadProperties(app_path);

            if (!app_path.equals(user_path)) {

                loadProperties(user_path);
            }

            // kinda hard to do this system property setting early enough as we musn't load the
            // config until after checking the "pass to existing process" code and this loads the
            // class InetAddress that caches the current system prop

            COConfigurationManager.addAndFireParameterListener("IPV6 Prefer Addresses", new ParameterListener() {
                private boolean done_something = false;

                public void parameterChanged(String name) {
                    boolean prefer_ipv6 = COConfigurationManager.getBooleanParameter(name);

                    boolean existing = !System.getProperty("java.net.preferIPv6Addresses", "false").equalsIgnoreCase("false");

                    // if user has overridden with a -D at az start then we don't want to let our config
                    // setting (which currently defaults to FALSE) to set this back

                    if (existing && !done_something) {

                        return;
                    }

                    if (existing != prefer_ipv6) {

                        done_something = true;

                        System.setProperty("java.net.preferIPv6Addresses", prefer_ipv6 ? "true" : "false");

                        try {
                            Field field = InetAddress.class.getDeclaredField("preferIPv6Address");

                            field.setAccessible(true);

                            field.setBoolean(null, prefer_ipv6);

                        } catch (Throwable e) {

                            Debug.out("Failed to update 'preferIPv6Address'", e);
                        }
                    }
                }
            });

            if (Constants.isWindowsVistaOrHigher && Constants.isJava7OrHigher) {

                COConfigurationManager.addAndFireParameterListener("IPV4 Prefer Stack", new ParameterListener() {
                    private boolean done_something = false;

                    public void parameterChanged(String name) {
                        boolean prefer_ipv4 = COConfigurationManager.getBooleanParameter(name);

                        boolean existing = !System.getProperty("java.net.preferIPv4Stack", "false").equalsIgnoreCase("false");

                        // if user has overridden with a -D at az start then we don't want to let our config
                        // setting (which currently defaults to FALSE) to set this back

                        if (existing && !done_something) {

                            return;
                        }

                        if (existing != prefer_ipv4) {

                            done_something = true;

                            System.setProperty("java.net.preferIPv4Stack", prefer_ipv4 ? "true" : "false");

                            try {
                                Class<?> plainSocketImpl = getClass().forName("java.net.PlainSocketImpl");

                                Field pref_field = plainSocketImpl.getDeclaredField("preferIPv4Stack");

                                pref_field.setAccessible(true);

                                pref_field.setBoolean(null, prefer_ipv4);

                                Field dual_field = plainSocketImpl.getDeclaredField("useDualStackImpl");

                                dual_field.setAccessible(true);

                                dual_field.setBoolean(null, !prefer_ipv4);

                            } catch (Throwable e) {

                                Debug.out("Failed to update 'preferIPv4Stack'", e);
                            }
                        }
                    }
                });
            }

            // socket connect/read timeouts

            int connect_timeout = COConfigurationManager.getIntParameter("Tracker Client Connect Timeout");
            int read_timeout = COConfigurationManager.getIntParameter("Tracker Client Read Timeout");

            if (Logger.isEnabled())
                Logger.log(new LogEvent(LOGID, "TrackerClient: connect timeout = " + connect_timeout + ", read timeout = " + read_timeout));

            System.setProperty("sun.net.client.defaultConnectTimeout", String.valueOf(connect_timeout * 1000));

            System.setProperty("sun.net.client.defaultReadTimeout", String.valueOf(read_timeout * 1000));

            if (COConfigurationManager.getBooleanParameter("Enable.Proxy")) {
                String host = COConfigurationManager.getStringParameter("Proxy.Host");
                String port = COConfigurationManager.getStringParameter("Proxy.Port");
                String user = COConfigurationManager.getStringParameter("Proxy.Username");
                String pass = COConfigurationManager.getStringParameter("Proxy.Password");

                if (user.trim().equalsIgnoreCase("<none>")) {
                    user = "";
                }

                if (COConfigurationManager.getBooleanParameter("Enable.SOCKS")) {
                    System.setProperty("socksProxyHost", host);
                    System.setProperty("socksProxyPort", port);

                    if (user.length() > 0) {
                        System.setProperty("java.net.socks.username", user);
                        System.setProperty("java.net.socks.password", pass);
                    }
                } else {
                    System.setProperty("http.proxyHost", host);
                    System.setProperty("http.proxyPort", port);
                    System.setProperty("https.proxyHost", host);
                    System.setProperty("https.proxyPort", port);

                    if (user.length() > 0) {
                        System.setProperty("http.proxyUser", user);
                        System.setProperty("http.proxyPassword", pass);
                    }
                }
            }

            SESecurityManager.initialise();
        } finally {

            class_mon.exit();
        }
    }

    protected static void loadProperties(String dir) {
        try {
            File prop_file = new File(dir, "azureus.properties");

            if (prop_file.exists()) {

                Logger.log(new LogEvent(LOGID, "Loading properties file from " + prop_file.getAbsolutePath()));

                Properties props = new Properties();

                InputStream is = new FileInputStream(prop_file);

                try {
                    props.load(is);

                    Iterator it = props.entrySet().iterator();

                    while (it.hasNext()) {

                        Map.Entry entry = (Map.Entry) it.next();

                        String key = (String) entry.getKey();
                        String value = (String) entry.getValue();

                        Logger.log(new LogEvent(LOGID, "    " + key + "=" + value));

                        System.setProperty(key, value);
                    }
                } finally {

                    is.close();
                }
            }
        } catch (Throwable e) {

        }
    }

    public static void checkConfiguration() {
        try {
            class_mon.enter();

            if (checked)
                return;
            checked = true;

            boolean changed = CustomizationManagerFactory.getSingleton().preInitialize();

            String last_version = COConfigurationManager.getStringParameter("azureus.version", "");

            String this_version = Constants.AZUREUS_VERSION;

            if (!last_version.equals(this_version)) {
                if (!Constants.getBaseVersion(last_version).equals(Constants.getBaseVersion())) {
                    COConfigurationManager.setParameter("Last Version", last_version);
                    new_version = true;
                }

                if (!COConfigurationManager.hasParameter("First Recorded Version", true)) {
                    COConfigurationManager.setParameter("First Recorded Version", last_version.length() == 0 ? this_version : last_version);
                } else {
                    String sFirstVersion = COConfigurationManager.getStringParameter("First Recorded Version");
                    String sMinVersion = Constants.compareVersions(sFirstVersion, this_version) > 0 ? this_version : sFirstVersion;
                    if (last_version.length() > 0) {
                        sMinVersion = Constants.compareVersions(sMinVersion, last_version) > 0 ? last_version : sMinVersion;
                    }
                    COConfigurationManager.setParameter("First Recorded Version", sMinVersion);
                }

                COConfigurationManager.setParameter("azureus.version", this_version);

                changed = true;
            }

            // migration from default-save-dir enable = true to false
            // if the user hadn't explicitly set a value then we want to stick with true

            if (last_version.length() == 0) { // this is a virgin installation, i.e. first time running, called only once ever

                new_install = true;

                // "last version" introduced at same time as the default save dir problem
                // which was the release after 2.2.0.0

                // only do this on an already existing configuration. Easiest way to test
                // for this is the "diagnostics.tidy_close" flag

                if (COConfigurationManager.doesParameterNonDefaultExist("diagnostics.tidy_close")) {

                    if (!COConfigurationManager.doesParameterNonDefaultExist("Tracker Port Enable")) {

                        COConfigurationManager.setParameter("Tracker Port Enable", true);

                        changed = true;
                    }
                }

                // enable Beginner user mode for first time
                if (!COConfigurationManager.doesParameterNonDefaultExist("User Mode")) {
                    COConfigurationManager.setParameter("User Mode", 0);
                    changed = true;
                }

                // make sure we set and save a random listen port
                if (!COConfigurationManager.doesParameterNonDefaultExist("TCP.Listen.Port")) {
                    int rand_port = RandomUtils.generateRandomNetworkListenPort();
                    COConfigurationManager.setParameter("TCP.Listen.Port", rand_port);
                    COConfigurationManager.setParameter("UDP.Listen.Port", rand_port);
                    COConfigurationManager.setParameter("UDP.NonData.Listen.Port", rand_port);
                    changed = true;

                }
            } else { // this is a pre-existing installation, called every time after first

                if // disable safe selector mode enabled at some point in the past if we're on java 6 or higher and/or not on windows
                (COConfigurationManager.getBooleanParameter("network.tcp.enable_safe_selector_mode")
                        && !(Constants.isWindows && (Constants.JAVA_VERSION.startsWith("1.4") || Constants.JAVA_VERSION.startsWith("1.5")))) {
                    COConfigurationManager.removeParameter("network.tcp.enable_safe_selector_mode");
                    changed = true;
                }

                // transition from tracker-only port override to global port override
                if (COConfigurationManager.doesParameterNonDefaultExist("TCP.Announce.Port")) {
                    COConfigurationManager.setParameter("TCP.Listen.Port.Override", COConfigurationManager.getStringParameter("TCP.Announce.Port",
                            ""));
                    COConfigurationManager.removeParameter("TCP.Announce.Port");
                    changed = true;
                }

                // enable Advanced user mode for existing users by default, to ease 2304-->2306 migrations
                if (!COConfigurationManager.doesParameterNonDefaultExist("User Mode")) {
                    COConfigurationManager.setParameter("User Mode", 2);
                    changed = true;
                }
            }

            // initial UDP port is same as TCP

            if (!COConfigurationManager.doesParameterNonDefaultExist("UDP.Listen.Port")) {
                COConfigurationManager.setParameter("UDP.Listen.Port", COConfigurationManager.getIntParameter("TCP.Listen.Port"));

                changed = true;
            }

            // remove separate DHT udp port config and migrate to main UDP port above

            if (!COConfigurationManager.getBooleanParameter("Plugin.DHT.dht.portdefault", true)) {

                COConfigurationManager.removeParameter("Plugin.DHT.dht.portdefault");

                int tcp_port = COConfigurationManager.getIntParameter("TCP.Listen.Port");
                int udp_port = COConfigurationManager.getIntParameter("UDP.Listen.Port");

                int dht_port = COConfigurationManager.getIntParameter("Plugin.DHT.dht.port", udp_port);

                if (dht_port != udp_port) {

                    // if tcp + udp are currently different then we leave them as is and migrate
                    // dht to the udp one. Otherwise we change the core udp to be that of the dht

                    if (tcp_port == udp_port) {

                        COConfigurationManager.setParameter("UDP.Listen.Port", dht_port);
                    }
                }

                changed = true;
            }

            // reintroduce separate non-data UDP port yto separtate data from dht/UDP tracker

            if (!COConfigurationManager.doesParameterNonDefaultExist("UDP.NonData.Listen.Port")) {
                COConfigurationManager.setParameter("UDP.NonData.Listen.Port", COConfigurationManager.getIntParameter("UDP.Listen.Port"));

                changed = true;
            }

            // fix up broken config when multi-udp not enabled but values differ

            if (!COConfigurationManager.ENABLE_MULTIPLE_UDP_PORTS) {

                int udp1 = COConfigurationManager.getIntParameter("UDP.Listen.Port");
                int udp2 = COConfigurationManager.getIntParameter("UDP.NonData.Listen.Port");

                if (udp1 != udp2) {

                    COConfigurationManager.setParameter("UDP.NonData.Listen.Port", udp1);

                    changed = true;
                }
            }

            boolean randomize_ports = COConfigurationManager.getBooleanParameter("Listen.Port.Randomize.Enable");

            if (randomize_ports) {

                String random_range = COConfigurationManager.getStringParameter("Listen.Port.Randomize.Range");

                if (random_range == null || random_range.trim().length() == 0) {

                    random_range = RandomUtils.LISTEN_PORT_MIN + "-" + RandomUtils.LISTEN_PORT_MAX;

                } else {

                    random_range = random_range.trim();
                }

                int min_port = RandomUtils.LISTEN_PORT_MIN;
                int max_port = RandomUtils.LISTEN_PORT_MAX;

                String[] bits = random_range.split("-");

                boolean valid = bits.length == 2;

                if (!valid) {

                    // try alternative split based on any non-numeric char (there are lots of unicode chars that
                    // look like a - sign...)

                    char[] chars = random_range.toCharArray();

                    for (int i = 0; i < chars.length - 1; i++) {

                        if (!Character.isDigit(chars[i])) {

                            bits = new String[] { random_range.substring(0, i), random_range.substring(i + 1) };

                            valid = true;

                            break;
                        }
                    }
                }

                if (valid) {

                    String lhs = bits[0].trim();

                    if (lhs.length() > 0) {

                        try {
                            min_port = Integer.parseInt(lhs);

                            valid = min_port > 0 && min_port < 65536;

                        } catch (Throwable e) {

                            valid = false;
                        }
                    }

                    String rhs = bits[1].trim();

                    if (rhs.length() > 0) {

                        try {
                            max_port = Integer.parseInt(rhs);

                            valid = max_port > 0 && max_port < 65536;

                        } catch (Throwable e) {

                            valid = false;
                        }
                    }
                }

                if (valid) {

                    boolean randomize_together = COConfigurationManager.getBooleanParameter("Listen.Port.Randomize.Together");

                    if (randomize_together) {

                        int port = RandomUtils.generateRandomNetworkListenPort(min_port, max_port);

                        COConfigurationManager.setParameter("TCP.Listen.Port", port);
                        COConfigurationManager.setParameter("UDP.Listen.Port", port);
                        COConfigurationManager.setParameter("UDP.NonData.Listen.Port", port);

                    } else {

                        int old_udp1 = COConfigurationManager.getIntParameter("UDP.Listen.Port");
                        int old_udp2 = COConfigurationManager.getIntParameter("UDP.NonData.Listen.Port");

                        int port1 = RandomUtils.generateRandomNetworkListenPort(min_port, max_port);

                        COConfigurationManager.setParameter("TCP.Listen.Port", port1);

                        int port2 = RandomUtils.generateRandomNetworkListenPort(min_port, max_port);

                        COConfigurationManager.setParameter("UDP.Listen.Port", port2);

                        if (old_udp1 == old_udp2) {

                            COConfigurationManager.setParameter("UDP.NonData.Listen.Port", port2);

                        } else {

                            int port3 = RandomUtils.generateRandomNetworkListenPort(min_port, max_port);

                            COConfigurationManager.setParameter("UDP.NonData.Listen.Port", port3);
                        }
                    }
                }
            }

            int tcp_port = COConfigurationManager.getIntParameter("TCP.Listen.Port");

            // reset invalid ports - single-instance socket port and (small) magnet uri listener port range

            if (tcp_port == Constants.INSTANCE_PORT || (tcp_port >= 45100 && tcp_port <= 45103)) {

                int new_tcp_port = RandomUtils.generateRandomNetworkListenPort();

                COConfigurationManager.setParameter("TCP.Listen.Port", new_tcp_port);

                if (COConfigurationManager.getIntParameter("UDP.Listen.Port") == tcp_port) {

                    COConfigurationManager.setParameter("UDP.Listen.Port", new_tcp_port);
                }

                if (COConfigurationManager.getIntParameter("UDP.NonData.Listen.Port") == tcp_port) {

                    COConfigurationManager.setParameter("UDP.NonData.Listen.Port", new_tcp_port);
                }

                changed = true;
            }

            // migrate to split tracker client/server key config

            if (!COConfigurationManager.doesParameterDefaultExist("Tracker Key Enable Client")) {

                boolean old_value = COConfigurationManager.getBooleanParameter("Tracker Key Enable");

                COConfigurationManager.setParameter("Tracker Key Enable Client", old_value);

                COConfigurationManager.setParameter("Tracker Key Enable Server", old_value);

                changed = true;
            }

            int maxUpSpeed = COConfigurationManager.getIntParameter("Max Upload Speed KBs", 0);
            int maxDownSpeed = COConfigurationManager.getIntParameter("Max Download Speed KBs", 0);

            if (maxUpSpeed > 0 && maxUpSpeed < COConfigurationManager.CONFIG_DEFAULT_MIN_MAX_UPLOAD_SPEED
                    && (maxDownSpeed == 0 || maxDownSpeed > (2 * maxUpSpeed))) {

                changed = true;
                COConfigurationManager.setParameter("Max Upload Speed KBs", COConfigurationManager.CONFIG_DEFAULT_MIN_MAX_UPLOAD_SPEED);
            }

            int peersRatio = COConfigurationManager.getIntParameter("Stop Peers Ratio", 0);
            if (peersRatio > 14) {
                COConfigurationManager.setParameter("Stop Peers Ratio", 14);
                changed = true;
            }

            int minQueueingShareRatio = COConfigurationManager.getIntParameter("StartStopManager_iFirstPriority_ShareRatio");
            if (minQueueingShareRatio < 500) {
                COConfigurationManager.setParameter("StartStopManager_iFirstPriority_ShareRatio", 500);
                changed = true;
            }

            int iSeedingMin = COConfigurationManager.getIntParameter("StartStopManager_iFirstPriority_SeedingMinutes");
            if (iSeedingMin < 90 && iSeedingMin != 0) {
                COConfigurationManager.setParameter("StartStopManager_iFirstPriority_SeedingMinutes", 90);
                changed = true;
            }

            int iDLMin = COConfigurationManager.getIntParameter("StartStopManager_iFirstPriority_DLMinutes");
            if (iDLMin < 60 * 3 && iDLMin != 0) {
                COConfigurationManager.setParameter("StartStopManager_iFirstPriority_DLMinutes", 60 * 3);
                changed = true;
            }

            int iIgnoreSPRatio = COConfigurationManager.getIntParameter("StartStopManager_iFirstPriority_ignoreSPRatio");
            if (iIgnoreSPRatio < 10 && iIgnoreSPRatio != 0) {
                COConfigurationManager.setParameter("StartStopManager_iFirstPriority_ignoreSPRatio", 10);
                changed = true;
            }

            String uniqueId = COConfigurationManager.getStringParameter("ID", null);
            if (uniqueId == null || uniqueId.length() != 20) {
                uniqueId = RandomUtils.generateRandomAlphanumerics(20);
                COConfigurationManager.setParameter("ID", uniqueId);
                changed = true;
            }

            int cache_max = COConfigurationManager.getIntParameter("diskmanager.perf.cache.size");
            if (cache_max > COConfigurationManager.CONFIG_CACHE_SIZE_MAX_MB) {
                COConfigurationManager.setParameter("diskmanager.perf.cache.size", COConfigurationManager.CONFIG_CACHE_SIZE_MAX_MB);
                changed = true;
            }
            if (cache_max < 1) { // oops
                COConfigurationManager.setParameter("diskmanager.perf.cache.size", 4);
                changed = true;
            }

            /**
             * Special Patch for OSX users
             */
            if (Constants.isOSX) {
                boolean sound = COConfigurationManager.getBooleanParameter("Play Download Finished", true);
                // Command + Q destroys the window, then notifies SWT, making it
                // hard to do a confirmation exit.
                boolean confirmExit = COConfigurationManager.getBooleanParameter("confirmationOnExit");

                if (sound || confirmExit) {
                    COConfigurationManager.setParameter("Play Download Finished", false);
                    COConfigurationManager.setParameter("confirmationOnExit", false);
                    changed = true;
                }
            }

            if (Constants.isOSX) {
                if (COConfigurationManager.getBooleanParameter("enable_small_osx_fonts")) {
                    System.setProperty("org.eclipse.swt.internal.carbon.smallFonts", "1");
                } else {
                    System.getProperties().remove("org.eclipse.swt.internal.carbon.smallFonts");
                }
                System.setProperty("org.eclipse.swt.internal.carbon.noFocusRing", "1");
            }

            // remove a trailing slash, due to user manually entering the path in config
            String[] path_params =
                    { "Default save path", "General_sDefaultTorrent_Directory", "Watch Torrent Folder Path", "Completed Files Directory" };
            for (int i = 0; i < path_params.length; i++) {
                if (path_params[i].endsWith(SystemProperties.SEP)) {
                    String new_path = path_params[i].substring(0, path_params[i].length() - 1);
                    COConfigurationManager.setParameter(path_params[i], new_path);
                    changed = true;
                }
            }

            // 2105 removed the language file web-update functionality,
            // but old left-over MessagesBundle.properties files in the user dir
            // cause display text problems, so let's delete them.
            if (ConfigurationManager.getInstance().doesParameterNonDefaultExist("General_bEnableLanguageUpdate")) {
                File user_dir = new File(SystemProperties.getUserPath());
                File[] files = user_dir.listFiles(new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                        if (name.startsWith("MessagesBundle") && name.endsWith(".properties")) {
                            return true;
                        }
                        return false;
                    }
                });

                if (files != null) {
                    for (int i = 0; i < files.length; i++) {
                        File file = files[i];
                        if (file.exists()) {
                            if (Logger.isEnabled())
                                Logger.log(new LogEvent(LOGID, LogEvent.LT_WARNING, "ConfigurationChecker:: removing old language file: "
                                        + file.getAbsolutePath()));
                            file.renameTo(new File(file.getParentFile(), "delme" + file.getName()));
                        }
                    }
                }
                ConfigurationManager.getInstance().removeParameter("General_bEnableLanguageUpdate");
                changed = true;
            }

            // 4511: confirm.delete.content (boolean) changed to tb..confirm.delete.content (long)
            final String CFG_CONFIRM_DELETE_CONTENT = "confirm.delete.content";
            if (ConfigurationManager.getInstance().doesParameterNonDefaultExist(CFG_CONFIRM_DELETE_CONTENT)) {
                boolean confirm = COConfigurationManager.getBooleanParameter(CFG_CONFIRM_DELETE_CONTENT);
                if (!confirm && !ConfigurationManager.getInstance().doesParameterNonDefaultExist("tb.confirm.delete.content")) {
                    COConfigurationManager.setParameter("tb.confirm.delete.content", 1);
                }
                COConfigurationManager.removeParameter(CFG_CONFIRM_DELETE_CONTENT);
                changed = true;
            }

            if (FeatureAvailability.isAutoSpeedDefaultClassic()) {

                ConfigurationDefaults.getInstance().addParameter(SpeedManagerImpl.CONFIG_VERSION, 1); // 1 == classic, 2 == beta
            }

            int check_level = COConfigurationManager.getIntParameter("config.checker.level", 0);

            if (check_level < 1) {

                COConfigurationManager.setParameter("config.checker.level", 1);

                changed = true;

                // initial setting of auto-config for upload slots etc

                String[] params =
                        { "Max Uploads", "enable.seedingonly.maxuploads", "Max Uploads Seeding", "Max.Peer.Connections.Per.Torrent",
                                "Max.Peer.Connections.Per.Torrent.When.Seeding.Enable", "Max.Peer.Connections.Per.Torrent.When.Seeding",
                                "Max.Peer.Connections.Total", "Max Seeds Per Torrent" };

                boolean has_been_set = false;

                for (String param : params) {

                    if (COConfigurationManager.doesParameterNonDefaultExist(param)) {

                        has_been_set = true;

                        break;
                    }
                }

                if (has_been_set) {

                    COConfigurationManager.setParameter("Auto Adjust Transfer Defaults", false);
                }
            }

            if (Constants.isOSX && check_level < 2) {

                // turn on piece-reorder mode for osx

                COConfigurationManager.setParameter("config.checker.level", 2);

                changed = true;

                if (!COConfigurationManager.getBooleanParameter("Zero New")) {

                    COConfigurationManager.setParameter("Enable reorder storage mode", true);
                }
            }

            // check_level 3 was used temporarily

            if (COConfigurationManager.doesParameterNonDefaultExist("Watch Torrent Folder Interval")) {

                long mins = COConfigurationManager.getIntParameter("Watch Torrent Folder Interval");

                COConfigurationManager.removeParameter("Watch Torrent Folder Interval");

                COConfigurationManager.setParameter("Watch Torrent Folder Interval Secs", 60 * mins);

                changed = true;
            }

            if (changed) {
                COConfigurationManager.save();
            }

            setupVerifier();

        } finally {

            class_mon.exit();
        }

        ConfigurationDefaults.getInstance().runVerifiers();
    }

    private static void setupVerifier() {
        SimpleTimer.addEvent("ConfigCheck:ver", SystemTime.getOffsetTime(10 * 1000), new TimerEventPerformer() {

            private TimerEventPeriodic event;

            public void perform(TimerEvent ev) {
                runVerifier();

                if (event == null) {

                    long freq = COConfigurationManager.getLongParameter("Config Verify Frequency");

                    if (freq > 0) {

                        freq = Math.max(freq, 5 * 60 * 1000);

                        event = SimpleTimer.addPeriodicEvent("ConfigCheck:ver", freq, this);
                    }
                }
            }
        });
    }

    private static void runVerifier() {
        try {
            PlatformManager pm = PlatformManagerFactory.getPlatformManager();

            if (pm.hasCapability(PlatformManagerCapabilities.RunAtLogin)) {

                boolean start_on_login = COConfigurationManager.getBooleanParameter("Start On Login");

                if (pm.getRunAtLogin() != start_on_login) {

                    pm.setRunAtLogin(start_on_login);
                }
            }

            if (pm.hasCapability(PlatformManagerCapabilities.RegisterFileAssociations)) {

                boolean auto_reg = COConfigurationManager.getBooleanParameter("Auto Register App");

                if (auto_reg) {

                    pm.registerApplication();
                }
            }
        } catch (Throwable e) {

            Debug.out(e);
        }
    }

    public static final boolean isNewInstall() {
        return (new_install);
    }

    public static final boolean isNewVersion() {
        return (new_version);
    }
}
